function varargout = TLSfchartDlg(action,varargin)

% TL_SFCHART_DLG manages the user interface for SF Chart objects in TargetLink.
%
% SYNTAX dlgInfo = TLSfchartDlg('GetDlgInfo')
%   gets dialog info of SF Chart objects in TargetLink
%
%   INPUT ARGUMENTS
%   - / -
%
%   OUTPUT ARGUMENTS
%   dlgInfo         dialog information contains pageNames etc.
%
% SYNTAX [sheetDims,ctrlPos] = TLSfchartDlg('CtrlPositions', pageName, commonGeom, dlgInfo, sheetDims);
%   calculates the control positions of all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   commonGeom      common geometry data
%   dlgInfo         dialog information contains pageNames etc.
%   sheetDims       dimension of sheet
%
%   OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% SYNTAX dlgdata = TLSfchartDlg('Create', pageName, dlgfig, dlgdata);
%   creates all controls of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%
% SYNTAX [dlgdata, bModified] = TLSfchartDlg('Manage', pageName, dlgfig, dlgdata, pageAction);
%   manages all actions of dialog page: <pageName>
%
%   INPUT ARGUMENTS
%   pageName        name of current page
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageAction      modified control of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%   bModified       flag = 1, if dialog data are modified, =0 otherwise
%
% SYNTAX [dlgdata,bModified] = TLSfchartDlg('Update', dlgfig, dlgdata, pageNum);
%   updates all controls of dialog page: <pageNum>
%
%   INPUT ARGUMENTS
%   dlgfig          figure handle
%   dlgdata         dialog data
%   pageNum         number of current page
%
%   OUTPUT ARGUMENTS
%   dlgdata         modified dialog data


% Author(s): C.Witte, D. Andoleit
% $RCSfile: TLSfchartDlg.m $
% $ProjectName: e:/ARC/Components/HostSW/SimulinkBlocksets/TLBlocksets/StateflowBlockset/Sources/MSrc/project.pj $
% $Revision: 1.4 $
% $Date: 2011/11/23 14:15:09MEZ $
%
% Copyright ?2011 dSPACE GmbH. All rights reserved.


% branch depending on action
switch action,
    
    case 'GetDlgInfo'
        hSFObject = varargin{1};
        dlgInfo = tl_get_dlginfodefaults('tlutil');
        titleName = tl_classify_sfobject(hSFObject);
        pathinfo = tl_pathinfo(hSFObject);
        dlgInfo.title = sprintf('TargetLink %s: %s', titleName, pathinfo.shortDisplayName);
        % overwrite general settings
        dlgInfo.bShowBlock = 1;
        dlgInfo.bDateLabel = 0;
        [data,dlgInfo.extdata] = get_tlcg_data(hSFObject);
        
        % return structure holding the names of tabs
        dlgInfo.pageNames = { ...
            'Options'; ...
            'Arguments'};
        
        varargout{1} = dlgInfo;
        varargout{2} = data;
        
    case 'CtrlPositions',
        % call function which handles different pages
        [sheetDims, ctrlPos] = FcnGeneralCtrlPositions(varargin{1}, varargin{2}, varargin{4});
        varargout{1} = sheetDims;
        varargout{2} = ctrlPos;
        
    case 'Create'
        % call function which handles different pages
        dlgdata = FcnCreateGeneral(varargin{1}, varargin{2}, varargin{3});
        varargout{1} = dlgdata;
        
    case 'Manage'
        % call function which handles different pages
        [dlgdata, bModified] = FcnManageGeneral(varargin{1}, varargin{2}, varargin{3}, varargin{4});
        varargout{1} = dlgdata;
        varargout{2} = bModified;
        
    case 'ManageSystemIcons',
        dlgfig     = varargin{1};
        dlgdata    = varargin{2};
        pageAction = varargin{3};
        [dlgdata, bModified] = FcnManageSystemIcons(dlgfig,dlgdata,pageAction);
        varargout{1} = dlgdata;
        varargout{2} = bModified;
        
    case 'Update'
        dlgfig    = varargin{1};
        dlgdata   = varargin{2};
        pageNum   = varargin{3};
        dlgdata = FcnUpdateGeneral(dlgfig, dlgdata, pageNum);
        varargout{1} = dlgdata;
        
    case 'Apply'
        dlgdata  = varargin{2};
        bClose   = varargin{3};
        [dlgdata, bClose] = tl_apply_blockdata(dlgdata, bClose);
        varargout{1} = dlgdata;
        varargout{2} = bClose;
        
    otherwise
        error(['Invalid action: "' action '"']);
        
end; %switch


%-----------------------------------------------------------------------------------------
% FcnManageSystemIcons manages actions of toolbar icons
%
% INPUT ARGUMENTS
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   action      action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageSystemIcons(dlgfig, dlgdata, action) %#ok

bModified = false;
chartPath = tl_get_sf_path(dlgdata.model,'model','on');
hChart = get_param(chartPath,'Handle');

switch action
    case 'EditCode'
        % look for associated production code file
        [codefile,blockstr] = get_codefile(hChart{1});
        if ~isempty(codefile)
            codeedit(codefile,blockstr);
        end
        
    case 'ViewCode'
        tl_create_links_to_model('ShowComputation',hChart{1});
        
    otherwise
        error('Invalid callback');
        
end % switch(action)


%-------------------------------------------------------------------------------
% FcnGeneralCtrlPositions handles "Control Positions" call for the different pages of the dialog
%
% INPUT ARGUMENTS
%   pageName        name of the page
%   commonGeom      common Geometries like text size, ...
%   sheetDims       sheetDims
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%-------------------------------------------------------------------------------
function [sheetDims, ctrlPos] = FcnGeneralCtrlPositions(pageName, commonGeom, sheetDims)
switch pageName,
    case 'Options',
        [sheetDims,ctrlPos] = FcnOptionsCtrlPositions(commonGeom, sheetDims);
    case 'Arguments'
        [sheetDims,ctrlPos] = FcnArgumentsCtrlPositions(commonGeom, sheetDims);
    otherwise
        error(['Nonexistent page ''' action'''']);
end; %switch
% end of function FcnGeneralCtrlPositions


%-------------------------------------------------------------------------------
% FcnCreateGeneral handles "Create" call for the different pages of the dialog
%
% INPUT ARGUMENTS
%   pageName    name of the page
%   dlgfig      handle of dialgo figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-------------------------------------------------------------------------------
function  dlgdata = FcnCreateGeneral(pageName, dlgfig, dlgdata)

pageNum  = strcmp(pageName,dlgdata.pageNames);
% branch depending on page name
switch pageName
    case 'Options'
        dlgdata = FcnCreateOptionsPage(pageNum,dlgfig,dlgdata);
    case 'Arguments'
        dlgdata = FcnCreateArgumentsPage(pageNum,dlgfig,dlgdata);
    otherwise
        error(['Nonexistent page ''' action'''']);
end; %switch
dlgdata.pageData{pageNum}.ctrlPos = [];
% end of function FcnCreateGeneral


%-------------------------------------------------------------------------------
% FcnManageGeneral handles "Manage" call for the different pages of the dialog
%
% INPUT ARGUMENTS
%   pageName        name of the page
%   dlgfig          handle of dialgo figure
%   dlgdata         dialog data
%   pageAction      dependend of the control that has been changed on the page
%
% OUTPUT ARGUMENTS
%   dlgdata         modified dialog data
%   bModified       1 if data has been modified, zero otherwise
%-------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageGeneral(pageName, dlgfig, dlgdata, pageAction)
% branch depending on page name
pageNum    = strcmp(pageName,dlgdata.pageNames);
switch pageName
    case 'Options'
        [dlgdata,bModified] = FcnManageOptionsPage(pageNum,dlgfig,dlgdata,pageAction);
    case 'Arguments'
        [dlgdata,bModified] = FcnManageArgumentsPage(pageNum,dlgfig,dlgdata,pageAction);
    otherwise
        error(['Nonexistent page ''' action'''']);
end; %switch
% end of function FcnManageGeneral


%------------------------------------------------------------------------------
% FcnUpdateGeneral handles "Update" call for the different pages of the dialog
%
% INPUT ARGUMENTS
%   dlgfig      handle of dialog figure
%   dlgdata     dialog data
%   pageNum     number of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-------------------------------------------------------------------------------
function dlgdata = FcnUpdateGeneral(dlgfig, dlgdata, pageNum)

pageName = dlgdata.pageNames{pageNum};
% branch depending on page name
switch pageName
    case 'Options'
        FcnUpdateOptionsPage(dlgfig, dlgdata, pageNum);
    case 'Arguments'
        FcnUpdateArgumentsPage(dlgfig, dlgdata, pageNum)
    otherwise
        error(['Nonexistent page ''' action'''']);
end; %switch
% end of function FcnCreateGeneral


%===============================================================================
%
%                                 Options Page
%
%===============================================================================
%-------------------------------------------------------------------------------
% FcnOptionsCtrlPosition calculates positions for all controls on option page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%   sheetDims       dimension of sheet
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-------------------------------------------------------------------------------
function [sheetDims,ctrlPos] = FcnOptionsCtrlPositions(commonGeom,sheetDims)

% Get the sizes of the edit fields, checkboxes, buttons and labels (last is
% determined from the longest label).
strings_and_styles = {
    'Make function reusable:',      'checkbox'; ...
    'Auxiliary function class:',    'text'; ...
    repmat('m',1,30),               'edit'; ...
    'n',                            'pushbutton'};
[reuseFcnCheckboxSize, ...
    labelSize, ...
    editSize, ...
    dotPushButtonSize] = ds_get_uicontrol_sizes(commonGeom,strings_and_styles);

% correct height, because on some platforms icon overlapped button boundary; icon height is 18 pixel.
dotPushButtonSize(2) = max(22, dotPushButtonSize(2));

dotButtonSize = [2*dotPushButtonSize(1) dotPushButtonSize(2)];

% Get the page partitioning and row/column spacing.
widths = [labelSize(1) editSize(1) dotButtonSize(1)];
[col,colWidth,colDelta,rowDelta] = ds_get_gui_columns(widths,commonGeom);

% All groupboxes in this page have the same width, which is the maximum of
% the 'needed' width and the size of the page.
OptGroupboxWidth = sum(colWidth) + 2/3 * colDelta + 2 * commonGeom.frameSideEdgeBuffer;
OptGroupboxWidth = max(OptGroupboxWidth, ...
    sheetDims(1) - 2 * commonGeom.sheetSideEdgeBuffer);

% Position of code file options groupbox.
codeFileOptGroupboxHeight = ...
    commonGeom.frameTopEdgeBuffer + ...
    commonGeom.editHeight + ...
    commonGeom.frameBottomEdgeBuffer;
cx = commonGeom.figSideEdgeBuffer + commonGeom.sheetSideEdgeBuffer;
cy = commonGeom.bottomSheetOffset + commonGeom.sheetBottomEdgeBuffer;
ctrlPos.codeFileOptGroupbox = [cx,cy,OptGroupboxWidth,codeFileOptGroupboxHeight];

% Position of "code file name" label and edit field.
cx = col(1);
cy = commonGeom.frameBottomEdgeBuffer;
ctrlPos.cFileLabelExt = [cx cy labelSize];

ctrlPos.cFileLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.cFileEdit = [cx cy editSize];

% Position of code options groupbox.
codeOptGroupboxHeight = ...
    commonGeom.frameTopEdgeBuffer ...
    + 8 * editSize(2) + 7 * rowDelta ...
    + commonGeom.frameBottomEdgeBuffer;
cx = ctrlPos.codeFileOptGroupbox(1);
cy = ctrlPos.codeFileOptGroupbox(2) + codeFileOptGroupboxHeight...
    + commonGeom.textHeight;
ctrlPos.codeOptGroupbox =  [cx,cy,OptGroupboxWidth,codeOptGroupboxHeight];

% Position of "make functions reusable" checkbox.
cx = col(1);
cy = commonGeom.frameBottomEdgeBuffer;
ctrlPos.reuseFcnCheckbox = [cx cy reuseFcnCheckboxSize];

% Position of "Subsystem ID" Label and Edit field
cy = cy + reuseFcnCheckboxSize(2) + rowDelta;
ctrlPos.subsystemIDLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.subsystemIDEdit = [cx cy editSize];

% Position of "entry function class" label, edit and browse.
cx = col(1);
cy = cy + editSize(2) + rowDelta;
ctrlPos.entryFcnClassLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.entryFcnClassEdit = [cx cy editSize];
% select button
cx = col(3);
ctrlPos.entryFcnClassSelectButton = [cx cy dotButtonSize];
% menu button
cx = cx + dotPushButtonSize(1);
ctrlPos.entryFcnClassMenuButton = [cx+2,cy+2,dotPushButtonSize(1)-4 dotPushButtonSize(2)-4];

% Position of "Init function class" label, edit and browse.
cx = col(1);
cy = cy + editSize(2) + rowDelta;
ctrlPos.initFcnClassLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.initFcnClassEdit = [cx cy editSize];
% select button
cx = col(3);
ctrlPos.initFcnClassSelectButton = [cx cy dotButtonSize];
% menu button
cx = cx + dotPushButtonSize(1);
ctrlPos.initFcnClassMenuButton = [cx+2,cy+2,dotPushButtonSize(1)-4 dotPushButtonSize(2)-4];

% Position of "Auxiliary function class" label, edit and browse.
cx = col(1);
cy = cy + editSize(2) + rowDelta;
ctrlPos.auxiliaryFcnClassLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.auxiliaryFcnClassEdit = [cx cy editSize];
% select button
cx = col(3);
ctrlPos.auxiliaryFcnClassSelectButton = [cx cy dotButtonSize];
% menu button
cx = cx + dotPushButtonSize(1);
ctrlPos.auxiliaryFcnClassMenuButton = [cx+2,cy+2,dotPushButtonSize(1)-4 dotPushButtonSize(2)-4];


% Position of "Step function class" label, edit and browse.
cx = col(1);
cy = cy + editSize(2) + rowDelta;
ctrlPos.stepFcnClassLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.stepFcnClassEdit = [cx cy editSize];
% select button
cx = col(3);
ctrlPos.stepFcnClassSelectButton = [cx cy dotButtonSize];
% menu button
cx = cx + dotPushButtonSize(1);
ctrlPos.stepFcnClassMenuButton = [cx+2,cy+2,dotPushButtonSize(1)-4 dotPushButtonSize(2)-4];

%  Position of "Step Function name" label, edit and force checkbox.
cx = col(1);
cy = cy + editSize(2) + rowDelta;
ctrlPos.functionNameLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.functionNameEdit = [cx cy editSize];

% Position of "Description" label and edit field.
cx = col(1);
cy = cy + editSize(2) + rowDelta;
ctrlPos.descLabel = [cx cy labelSize];
cx = col(2);
ctrlPos.fcnDescEdit = [cx cy editSize];

% Width and height of page.
width = OptGroupboxWidth + 2 * commonGeom.sheetSideEdgeBuffer;
height = commonGeom.sheetTopEdgeBuffer ...
    + ctrlPos.codeFileOptGroupbox(4) ...
    + ctrlPos.codeOptGroupbox(4) ...
    + commonGeom.textHeight ...
    + commonGeom.sheetBottomEdgeBuffer;

sheetDims = [width height];
% end of function FcnOptionsCtrlPositions


%-------------------------------------------------------------------------------
% FcnCreateOptionsPage creates the figure window
%
% INPUT ARGUMENTS
%   pageNum     number of the page
%   dlgfig      handle of dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%
% HINT:
% Edit fields and checkboxes are left empty,
% they are filled out with the block data in the update function.
%-------------------------------------------------------------------------------
function dlgdata = FcnCreateOptionsPage(pageNum,dlgfig,dlgdata)

ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;
pageName   = dlgdata.pageNames{pageNum};
defColor = get(0, 'DefaultUIControlBackgroundColor');

userDataMenuButton.cDataEnabled  = tl_get_icon('ArrowHeadDown_10x18', 'BackgroundColor', defColor);
userDataMenuButton.cDataDisabled = tl_get_icon('ArrowHeadDown_10x18_disabled');
userDataSelectButton.cDataEnabled  = tl_get_icon('Browse_Seperator_24x18', 'BackgroundColor', defColor);
userDataSelectButton.cDataDisabled = tl_get_icon('Browse_Seperator_24x18');

% Code file options groupbox
Children.codeFileOptGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Code file options'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.codeFileOptGroupbox);

Children.cFileLabel  = uicontrol( ...
    'Parent',             Children.codeFileOptGroupbox, ...
    'Style',              'text', ...
    'String',             'C code file name:', ...
    'Position',           ctrlPos.cFileLabel );

Children.cFileEdit  = uicontrol( ...
    'Parent',             Children.codeFileOptGroupbox, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.cFileEdit );

% Code options groupbox
Children.codeOptGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Code options'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.codeOptGroupbox);

Children.reuseFcnCheckbox = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'checkbox', ...
    'String',   'Make function reusable', ...
    'Position', ctrlPos.reuseFcnCheckbox);

% Subsystem ID
Children.subsystemIDLabel = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'text', ...
    'String',   'Subsystem ID:', ...
    'Position', ctrlPos.subsystemIDLabel);

Children.subsystemIDEdit = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'edit', ...
    'Position', ctrlPos.subsystemIDEdit);

% Entry function class
Children.entryFcnClassLabel = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'text', ...
    'String',   'Entry function class:', ...
    'Position', ctrlPos.entryFcnClassLabel);

Children.entryFcnClassEdit = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'edit', ...
    'Position', ctrlPos.entryFcnClassEdit);

Children.entryFcnClassSelectButton = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'pushbutton', ...
    'UserData', userDataSelectButton, ...
    'CData',    userDataSelectButton.cDataEnabled, ...
    'Position', ctrlPos.entryFcnClassSelectButton);

Children.entryFcnClassMenuButton = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'pushbutton', ...
    'UserData', userDataMenuButton, ...
    'CData',    userDataMenuButton.cDataEnabled, ...
    'Position', ctrlPos.entryFcnClassMenuButton);

entryCMenu = uicontextmenu('Parent', dlgfig);
set(Children.entryFcnClassEdit, 'UIContextMenu', entryCMenu);
set(Children.entryFcnClassMenuButton, 'UIContextMenu', entryCMenu);
menu.select = uimenu(entryCMenu, ...
    'Label', 'Select', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''entryFcnClassSelectButton'')',pageName));
menu.edit = uimenu(entryCMenu, ...
    'Label', 'Edit', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''entryFcnEditDDObject'')',pageName), ...
    'Separator','on');
menu.show = uimenu(entryCMenu, ...
    'Label', 'Show in DD Manager', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''entryFcnShowDDObject'')',pageName), ...
    'Separator','on');
set(entryCMenu, 'UserData', menu);

% Init function class
Children.initFcnClassLabel = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'text', ...
    'String',   'Init function class:', ...
    'Position', ctrlPos.initFcnClassLabel);

Children.initFcnClassEdit = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'edit', ...
    'Position', ctrlPos.initFcnClassEdit);

Children.initFcnClassSelectButton = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'pushbutton', ...
    'UserData', userDataSelectButton, ...
    'CData',    userDataSelectButton.cDataEnabled, ...
    'Position', ctrlPos.initFcnClassSelectButton);

Children.initFcnClassMenuButton = uicontrol( ...
    'Parent',            Children.codeOptGroupbox, ...
    'Style',             'pushbutton', ...
    'UserData',          userDataMenuButton, ...
    'CData',             userDataMenuButton.cDataEnabled, ...
    'Position',          ctrlPos.initFcnClassMenuButton);

initCMenu = uicontextmenu('Parent', dlgfig);
set(Children.initFcnClassEdit, 'UIContextMenu', initCMenu);
set(Children.initFcnClassMenuButton, 'UIContextMenu', initCMenu);
menu.select = uimenu(initCMenu, ...
    'Label', 'Select', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''initFcnClassSelectButton'')',pageName));
menu.edit = uimenu(initCMenu, ...
    'Label', 'Edit', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''initFcnEditDDObject'')',pageName), ...
    'Separator','on');
menu.show = uimenu(initCMenu, ...
    'Label', 'Show in DD Manager', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''initFcnShowDDObject'')',pageName), ...
    'Separator','on');
set(initCMenu, 'UserData', menu);

% auxiliary function class
Children.auxiliaryFcnClassLabel = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'text', ...
    'String',   'Auxiliary function class:', ...
    'Position', ctrlPos.auxiliaryFcnClassLabel);

Children.auxiliaryFcnClassEdit = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'edit', ...
    'Position', ctrlPos.auxiliaryFcnClassEdit);

Children.auxiliaryFcnClassSelectButton = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'pushbutton', ...
    'UserData', userDataSelectButton, ...
    'CData',    userDataSelectButton.cDataEnabled, ...
    'Position', ctrlPos.auxiliaryFcnClassSelectButton);

Children.auxiliaryFcnClassMenuButton = uicontrol( ...
    'Parent',            Children.codeOptGroupbox, ...
    'Style',             'pushbutton', ...
    'UserData',          userDataMenuButton, ...
    'CData',             userDataMenuButton.cDataEnabled, ...
    'Position',          ctrlPos.auxiliaryFcnClassMenuButton);

auxiliaryCMenu = uicontextmenu('Parent', dlgfig);
set(Children.auxiliaryFcnClassEdit, 'UIContextMenu', auxiliaryCMenu);
set(Children.auxiliaryFcnClassMenuButton, 'UIContextMenu', auxiliaryCMenu);
menu.select = uimenu(auxiliaryCMenu, ...
    'Label', 'Select', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''auxiliaryFcnClassSelectButton'')',pageName));
menu.edit = uimenu(auxiliaryCMenu, ...
    'Label', 'Edit', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''auxiliaryFcnEditDDObject'')',pageName), ...
    'Separator','on');
menu.show = uimenu(auxiliaryCMenu, ...
    'Label', 'Show in DD Manager', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''auxiliaryFcnShowDDObject'')',pageName), ...
    'Separator','on');
set(auxiliaryCMenu, 'UserData', menu);

% Function class
Children.stepFcnClassLabel = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'text', ...
    'String',   'Step function class:', ...
    'Position', ctrlPos.stepFcnClassLabel);

Children.stepFcnClassEdit = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'edit', ...
    'Position', ctrlPos.stepFcnClassEdit);

Children.stepFcnClassSelectButton = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'pushbutton', ...
    'UserData', userDataSelectButton, ...
    'CData',    userDataSelectButton.cDataEnabled, ...
    'Position', ctrlPos.stepFcnClassSelectButton);

Children.stepFcnClassMenuButton = uicontrol( ...
    'Parent',            Children.codeOptGroupbox, ...
    'Style',             'pushbutton', ...
    'UserData',          userDataMenuButton, ...
    'CData',             userDataMenuButton.cDataEnabled, ...
    'Position',          ctrlPos.stepFcnClassMenuButton);

stepCMenu = uicontextmenu('Parent', dlgfig);
set(Children.stepFcnClassEdit, 'UIContextMenu', stepCMenu);
set(Children.stepFcnClassMenuButton, 'UIContextMenu', stepCMenu);
menu.select = uimenu(stepCMenu, ...
    'Label', 'Select', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''stepFcnClassSelectButton'')',pageName));
menu.edit = uimenu(stepCMenu, ...
    'Label', 'Edit', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''stepFcnEditDDObject'')',pageName), ...
    'Separator','on');
menu.show = uimenu(stepCMenu, ...
    'Label', 'Show in DD Manager', ...
    'Callback', sprintf('tldlg(''%s'',gcbf,''stepFcnShowDDObject'')',pageName), ...
    'Separator','on');
set(stepCMenu, 'UserData', menu);

% Function name
Children.functionNameLabel = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'text', ...
    'String',   'Function name:', ...
    'Position', ctrlPos.functionNameLabel);

Children.functionNameEdit = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'edit', ...
    'Position', ctrlPos.functionNameEdit);

% Description
Children.descLabel = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'text', ...
    'String',   'Description:', ...
    'Position', ctrlPos.descLabel);

Children.fcnDescEdit = uicontrol( ...
    'Parent',   Children.codeOptGroupbox, ...
    'Style',    'edit', ...
    'Position', ctrlPos.fcnDescEdit);

dlgdata.pageData{pageNum}.children = Children;
% end of function FcnCreateOptionsPage


%-------------------------------------------------------------------------------
% FcnManageOptionsPage manages control actions of options page
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-------------------------------------------------------------------------------
function [dlgdata,bModified] = FcnManageOptionsPage(pageNum, dlgfig, dlgdata, pageAction) %#ok<INUSL>

% prepare needed data
bModified = false;
Children  = dlgdata.pageData{pageNum}.children;
data      = dlgdata.data;

% branch depending on action
switch pageAction
    case 'fcnDescEdit'
        data.description = get(Children.fcnDescEdit,'String');
        bModified = true;
    case {'stepFcnClassSelectButton', 'stepFcnClassEdit'}
        [data.stepfunctionclass, bModified] = FcnGetFcnClass(pageAction(13:end),...
            data.stepfunctionclass, Children.stepFcnClassEdit);
    case {'auxiliaryFcnClassSelectButton', 'auxiliaryFcnClassEdit'}
        [data.auxiliaryfunctionclass, bModified] = FcnGetFcnClass(pageAction(18:end),...
            data.auxiliaryfunctionclass, Children.auxiliaryFcnClassEdit);
    case {'initFcnClassSelectButton', 'initFcnClassEdit'}
        [data.initfunctionclass, bModified] = FcnGetFcnClass(pageAction(13:end),...
            data.initfunctionclass, Children.initFcnClassEdit);
    case {'entryFcnClassSelectButton', 'entryFcnClassEdit'}
        [data.entryfunctionclass, bModified] = FcnGetFcnClass(pageAction(14:end),...
            data.entryfunctionclass, Children.entryFcnClassEdit);
    case {'stepFcnClassMenuButton' 'auxiliaryFcnClassMenuButton' 'initFcnClassMenuButton' 'entryFcnClassMenuButton'},
        panelPos = get(Children.codeOptGroupbox, 'Position');
        FcnSetMenuPosition(Children.(pageAction), panelPos(1:2));
        bModified = true;
    case {'entryFcnEditDDObject', 'initFcnEditDDObject', 'auxiliaryFcnEditDDObject', ...
            'stepFcnEditDDObject'}
        % at the moment no dd function class dialog exists. This case should never happen.
    case {'entryFcnShowDDObject', 'initFcnShowDDObject', 'auxiliaryFcnShowDDObject', ...
            'stepFcnShowDDObject'}
        switch pageAction
            case 'entryFcnShowDDObject'
                selectedFcnClass = data.entryfunctionclass;
            case 'initFcnShowDDObject'
                selectedFcnClass = data.initfunctionclass;
            case 'auxiliaryFcnShowDDObject'
                selectedFcnClass = data.auxiliaryfunctionclass;
            case 'stepFcnShowDDObject'
                selectedFcnClass = data.stepfunctionclass;
        end
        if strcmp(selectedFcnClass, 'default') || isempty(selectedFcnClass)
            % jump to node in DD Manager
            dsddman('Select', '/Pool/FunctionClasses');
        else
            % jump to function object in DD Manager
            varPath = ['/Pool/FunctionClasses/' selectedFcnClass];
            dsddman('Select', varPath);
        end
    case 'functionNameEdit'
        data.functionname = FcnGetFcnName(Children.functionNameEdit, ...
            data.functionname, 'functionname');
        bModified = true;
    case 'subsystemIDEdit'
        subsystemID = tl_deblank(get(Children.subsystemIDEdit,'String'),2);
        % Check if subsystem ID is a valid string. If not, get alternative subsystem
        % ID (replace invalid characters by '_', no more than 10 characters).
        [ok, subsystemID] = FcnCheckSubsystemID(subsystemID);
        data.subsystemid = subsystemID;
        bModified = true;
    case 'cFileEdit'
        codefile = tl_deblank(get(Children.cFileEdit,'String'),2);
        % no detailed check if file name is ok. With TL 2.1 it was possible to use $S or
        % similar, therefore it is still possible
        [tmp,codefile,e]  = fileparts(codefile); %#ok<*ASGLU>
        while ~isempty(e),
            [tmp,codefile,e]  = fileparts(codefile);
        end
        data.codefile = codefile;
        bModified = true;
    case 'reuseFcnCheckbox'
        data.reuse = get(Children.reuseFcnCheckbox,'Value');
        bModified = true;
    otherwise
        error(['Invalid action ''' pageAction '''']);
end; %switch

dlgdata.data = data;
% end of function FcnManageOptionsPage


%-------------------------------------------------------------------------------
% FcnSetMenuPosition calculates position of contextmenu
%
% INPUT ARGUMENTS
%   ctrlHandle  handle of control
%   panelStart  cx position of panel
%
% OUTPUT ARGUMENTS
%   - / -
%-------------------------------------------------------------------------------
function FcnSetMenuPosition(ctrlHandle, panelStart)

pos = get(ctrlHandle, 'Position') + [panelStart 0 0];
cmenu = get(ctrlHandle, 'UIContextmenu');
commonGeom = ds_get_common_geometry;
textExtent = commonGeom.textExtent;
labelStrings = get(get(cmenu, 'Children'), 'Label');
maxext = 0;
for k = 1 : numel(labelStrings)
    set(textExtent, 'String', labelStrings{k});
    ext = get(textExtent, 'Extent');
    maxext = max(maxext, ext(3));
end
position = [pos(1)-32-maxext, pos(2)];
set(cmenu, 'Position', position, 'Visible', 'on');


%-------------------------------------------------------------------------------
% FcnUpdateOptionsPage updates the controls of the options tab
%
% INPUT ARGUMENTS
%   dlgfig      figure handle of dialog
%   dlgdata     dialog data
%   pageNum     page Number
%
% OUTPUT ARGUMENTS
%   - / -
%-------------------------------------------------------------------------------
function FcnUpdateOptionsPage(dlgfig, dlgdata, pageNum) %#ok<INUSL>

% early return if children are missing
Children = dlgdata.pageData{pageNum}.children;
if isempty(Children),
    return
end; %if

data = dlgdata.data;

% get the functionclasses
functionClass          = data.stepfunctionclass;
auxiliaryFunctionClass = data.auxiliaryfunctionclass;
initFunctionClass      = data.initfunctionclass;
entryFunctionClass     = data.entryfunctionclass;

% 'codefile' edit field is active
codefile = data.codefile;
codefileBgColor = 'w';
bCodefileEnable = 'on';

% Set the color of the Subsystem ID: red if not valid, black otherwise
[ok, data.subsystemid] =  FcnCheckSubsystemID(data.subsystemid);
if ok
    subsystemidColor = 'k';
else
    subsystemidColor = 'r';
end; %if

% If input of edit field is 'default', it has to be changed to 'default '
% to make it possible to display it
functionClass          = FcnChangeDefaultInput(functionClass);
auxiliaryFunctionClass = FcnChangeDefaultInput(auxiliaryFunctionClass);
initFunctionClass      = FcnChangeDefaultInput(initFunctionClass);
entryFunctionClass     = FcnChangeDefaultInput(entryFunctionClass);
functionName           = FcnChangeDefaultInput(data.functionname);
subsystemID            = FcnChangeDefaultInput(data.subsystemid);
description            = FcnChangeDefaultInput(data.description);

% if all functionclasses/names are enabled, background color of edit field is white
bgColor = 'w';
% Set enableAll from 1 or 0 to 'on' or 'off'
enableAll = flag2str(dlgdata.bIsFullVs);
IsFullVsON = flag2str(dlgdata.bIsFullVs);

% Set all fields which do not depend on other fields...
set([Children.subsystemIDEdit], ...
    'String',           subsystemID, ...
    'BackGroundColor',  'w', ...
    'Foregroundcolor',  subsystemidColor, ...
    'Enable',           IsFullVsON);
set([Children.initFcnClassEdit], ...
    'String',           initFunctionClass, ...
    'BackGroundColor',  'w', ...
    'Enable',           IsFullVsON);
set([Children.initFcnClassSelectButton], 'Enable', IsFullVsON);
set([Children.stepFcnClassEdit], ...
    'String',           functionClass, ...
    'BackGroundColor',  'w', ...
    'Enable',           IsFullVsON);
set([Children.stepFcnClassSelectButton], 'Enable', IsFullVsON);
set([Children.functionNameEdit], ...
    'String',           functionName, ...
    'BackGroundColor',  'w', ...
    'Enable',           IsFullVsON);
% make string single-line, because edit control can not have multi-line text
descString  = strrep(description, char(10),' ');
set([Children.fcnDescEdit], ...
    'String',           descString, ...
    'BackGroundColor',  'w', ...
    'Enable',           IsFullVsON);
set([Children.reuseFcnCheckbox], ...
    'Value',            data.reuse, ...
    'Enable',           IsFullVsON);

% Set all fields where the Enable state depends on other properties of the block:
% Auxiliary function class, name, force
set(Children.auxiliaryFcnClassEdit, ...
    'String',           auxiliaryFunctionClass, ...
    'Enable',           enableAll, ...
    'Backgroundcolor',  bgColor);
set([Children.auxiliaryFcnClassSelectButton], 'Enable', enableAll);

% Entry function class, name, force
set(Children.entryFcnClassEdit, ...
    'String',           entryFunctionClass, ...
    'Enable',           enableAll, ...
    'Backgroundcolor',  bgColor);
set([Children.entryFcnClassSelectButton], 'Enable', enableAll);
% label and browse buttons
set([Children.auxiliaryFcnClassLabel,  ...
    Children.entryFcnClassLabel],...
    'Enable',           enableAll);
set([Children.auxiliaryFcnClassSelectButton, Children.entryFcnClassSelectButton], ...
    'Enable',           enableAll);
% codefile and module
set(Children.cFileEdit, ...
    'String',           codefile, ...
    'BackGroundColor',  codefileBgColor, ...
    'Enable',           bCodefileEnable);

% set status of context menu controls:
entryClassCMenu     = get(Children.entryFcnClassEdit, 'UIContextMenu');
entryClassMenu      = get(entryClassCMenu, 'UserData');
initClassCMenu      = get(Children.initFcnClassEdit, 'UIContextMenu');
initClassMenu       = get(initClassCMenu, 'UserData');
auxiliaryClassCMenu = get(Children.auxiliaryFcnClassEdit, 'UIContextMenu');
auxiliaryClassMenu  = get(auxiliaryClassCMenu, 'UserData');
stepClassCMenu      = get(Children.stepFcnClassEdit, 'UIContextMenu');
stepClassMenu       = get(stepClassCMenu, 'UserData');
% "select" has same enable/disable status as the Browse Button
set([entryClassMenu.select, auxiliaryClassMenu.select], ...
    'Enable',       enableAll);
set([initClassMenu.select, stepClassMenu.select],...
    'Enable',       IsFullVsON);
% "edit" is always disabled since at the moment there is no corresponding dd dialog
set([entryClassMenu.edit, initClassMenu.edit, auxiliaryClassMenu.edit, stepClassMenu.edit], ...
    'Enable',       'off');
% "show" is disabled, if function class is invalid or empty
bMissingEntryDDFcn = ~isempty(entryFunctionClass) ...
    && ~(dsdd('Exist',entryFunctionClass , ...
    'Parent',       '/Pool/FunctionClasses', ...
    'ObjectKind',   'FunctionClass'));
bMissingAuxiliaryDDFcn = ~isempty(auxiliaryFunctionClass) ...
    && ~(dsdd('Exist',auxiliaryFunctionClass , ...
    'Parent',       '/Pool/FunctionClasses', ...
    'ObjectKind',   'FunctionClass'));
bMissingInitDDFcn = ~isempty(initFunctionClass) ...
    && ~(dsdd('Exist',initFunctionClass , ...
    'Parent',       '/Pool/FunctionClasses', ...
    'ObjectKind',   'FunctionClass'));
bMissingStepDDFcn = ~isempty(functionClass) ...
    && ~(dsdd('Exist',functionClass , ...
    'Parent',       '/Pool/FunctionClasses', ...
    'ObjectKind',   'FunctionClass'));
if ~bMissingEntryDDFcn  || strcmp(entryFunctionClass, 'default ')
    set(entryClassMenu.show, ...
        'Enable',            enableAll);
else
    set(entryClassMenu.show, ...
        'Enable',            'off');
end
if ~bMissingAuxiliaryDDFcn  || strcmp(auxiliaryFunctionClass, 'default ')
    set(auxiliaryClassMenu.show, ...
        'Enable',   enableAll);
else
    set(auxiliaryClassMenu.show, ...
        'Enable',    'off');
end

if ~bMissingInitDDFcn  || strcmp(initFunctionClass, 'default ')
    set(initClassMenu.show, ...
        'Enable',    IsFullVsON);
else
    set(initClassMenu.show, ...
        'Enable',    'off');
end

if ~bMissingStepDDFcn  || strcmp(functionClass, 'default ')
    set(stepClassMenu.show, ...
        'Enable',    IsFullVsON);
else
    set(stepClassMenu.show, ...
        'Enable',    'off');
end
% end of function FcnUpdateOptionsPage


%-------------------------------------------------------------------------------
% FcnGetFcnClass handles the function class edit field and browse buttons.
%
% INPUT ARGUMENTS
%   action      either 'Edit' or 'Browse'
%   fcnclass    old functionclass
%   editfield   field user edited
%
% OUTPUT ARGUMENTS
%   fcnclass    new functionclass:
%               - new class if it is valid or if the new AND old class are invalid
%               - old class if the new class is not valid but the old class is
%   update      indicates if the dialog has to be updated (Update not neccessary if
%               invalid class is replaced by invalid class)
%-------------------------------------------------------------------------------
function [fcnclass, bUpdate] = FcnGetFcnClass(action, fcnclass, editfield)

bUpdate = true;
switch action
    case 'SelectButton'
        % Browse button: Get new class from reference selection dialog
        newclass = dsdd( 'SelectObject', ...
            'CurrentPath',     fcnclass, ...
            'ObjectKind',      'FunctionClass');
        if ~isempty(newclass),
            bClassValid = FcnExistFcnClass(newclass);
        else
            bClassValid = false;
        end; %if
    case 'Edit'
        % Edit field: Get new class from edit field
        newclass = tl_deblank(get(editfield,'String'),2);
        bClassValid = FcnExistFcnClass(newclass);
    otherwise
        error(['Invalid action ''' action '''']);
end; %switch

if bClassValid
    %if new class is valid, return new class
    fcnclass = newclass;
elseif ~(dsdd('exist',fcnclass,'Parent','Pool/FunctionClasses') ...
        || strcmp(fcnclass,'default'))
    % neither new, nor old class is valid
    fcnclass = newclass;
    % Do not call update function if class has been changed from an invalid
    % name to an invalid name. Call of update function would trigger error message twice!
    bUpdate = false;
end; %if
% end of function FcnGetFcnClass


%-------------------------------------------------------------------------------
% FcnGetFcnName handles the function name edit field.
%
% INPUT ARGUMENTS
%   Edit        edit field which has been modified
%
% OUTPUT ARGUMENTS
%   fcnname     new functionname:
%               - new class if it is valid
%               - old name if the new name is not valid
%-------------------------------------------------------------------------------
function [fcnname] = FcnGetFcnName(editCtrl,oldfcnname,field)

newname = tl_deblank(get(editCtrl,'String'),2);

dataDesc = tl_manage_blockset('GetDataDescription', 'SFChart');
idxVar = strcmp(field, dataDesc(:,1));

% extract block variable description
[tmpName, ok] = tl_isvarname(newname,dataDesc{idxVar, 2}{1,5});

if ok
    % fcnname is valid name: take fcnname
    fcnname = newname;
else
    % fcnname is invalid name: take old fcnname
    ds_error_msg({ ...
        ['New value ''' newname ''' is not a valid function name!.']}, ...
        'Title','Invalid TargetLink function name');
    fcnname = oldfcnname;
end


%-------------------------------------------------------------------------------
% FcnExistFcnClass checks if functionclass exist in the current Data Dictionary.
%
% INPUT ARGUMENTS
%   functionclass   function class
%
% OUTPUT ARGUMENTS
%   bClassValid     1 if class exists in DD, zero otherwise
%   hFcnClass       handle in DD
%-------------------------------------------------------------------------------
function [bClassValid, hFcnClass] = FcnExistFcnClass(fcnclass)

% check if functionclass is a valid functionclass
[bClassValid,hFcnClass] = dsdd('exist',fcnclass,'Parent','Pool/FunctionClasses');
if strcmp(fcnclass,'default')
    % default class must not further be checked
    bClassValid = 1;
    return
elseif ~bClassValid,
    % function class does not exist in data dictionary
    ds_error_msg({ ...
        % ['There is no ''' functionclass ''' function class in the current Data Dictionary file.'], ...
        % 'Enter ''default'' or select an existing function class.'}, ...
        % 'MessageNumber',1219,'Title','Invalid function class');
        'The current function class identifier', ...
        ['   ' fcnclass], ...
        'is undefined. Supplement the function class section of', ...
        'your Data Dictionary file or select a defined function class.'}, ...
        'MessageNumber',1219,'Title','Invalid function class');
else
    objKind = dsdd('getAttribute',hFcnClass,'ObjectKind');
    if ~strcmpi(objKind ,'FunctionClass'),
        ds_error_msg({ ...
            'The current identifier', ...
            ['   ',fcnclass], ...
            ['does not specify a function class, but a ' objKind   ' object.']}, ...
            'MessageNumber',1218,'Title','Not a function class');
        bClassValid = 0;
    end; %if
end; %if
% end of function FcnExistFcnClass


%-------------------------------------------------------------------------------
% FcnCheckSubsystemID checks if the given Subsystem ID is correct, i.e. the string
%   complies with regular expression and is not too long.
%
% INPUT ARGUMENTS
%   subsystemID     subsystem ID
%
% OUTPUT ARGUMENTS
%   ok              1 if functionname is ok, zero otherwise
%   subsystemID     new subsystem ID
%-------------------------------------------------------------------------------
function [ok, subsystemID] =  FcnCheckSubsystemID(subsystemID)
ok = 1;
invalidChar = regexp(subsystemID,'[^a-zA-Z0-9_]');
if (~isempty(subsystemID)) && ((~isempty(invalidChar)) || (length(subsystemID) > 10)),
    % ID is invalid if it is not empty and invalid characters are used or ID is too long
    ok = 0;
    ds_error_msg({ ...
        ['You cannot use ''' subsystemID ''' as TargetLink subsystem ID.'], ...
        'Use only letters (a .. z, A .. Z), digits (0 .. 9) and underscores (_).', ...
        'The TargetLink subsystem ID shouldn''t be longer than 10 characters.'}, ...
        'Title','Invalid TargetLink subsystem ID');
    % Replace invalid characters by '_', abbreviate subsystem ID (max 10 characters)
    subsystemID(invalidChar) = '_';
    subsystemID = subsystemID(1:min(end,10));
end; %if
% end of function FcnCheckSubsystemID


%===============================================================================
%
%                                Arguments Page
%
%===============================================================================
%-------------------------------------------------------------------------------
% FcnArgumentsCtrlPosition calculates positions of blockspecific controls of arguments page
%
% INPUT ARGUMENTS
%   commonGeom      common geometrie information
%   sheetDims       dimension of sheet
%
% OUTPUT ARGUMENTS
%   sheetDims       modified dimension of sheet
%   ctrlPos         positions of controls
%
% HINT:
% Positions are calculated from the bottom left of the figure to avoid
% dependencies on figure size
%-------------------------------------------------------------------------------
function [sheetDims,ctrlPos] = FcnArgumentsCtrlPositions(commonGeom,sheetDims)

% get the sizes of the edit fields, checkboxes, buttons and labels (last is
% determined from the longest label)
strings_and_styles = {...
    repmat('m',1,40),            'edit'; ...
    'Scaling invariant',         'checkbox'; ...
    ' Update ',                  'pushbutton'; ...
    'Preferred order of function arguments:',   'text'; ...
    'Additional pointer arguments:',   'text'};
[scalingPropEditSize, ...
    scalInvCheckboxSize, ...
    updateModelPushButtonSize, ...
    fcnArgsOrderLabelSize, ...
    additionalArgsLabelSize] = ds_get_uicontrol_sizes(commonGeom,strings_and_styles);

% get page partitioning and row/column spacing
widths = scalingPropEditSize(1);
[tmp,tmp,colDelta,tmp] = ds_get_gui_columns(widths,commonGeom); %#ok

% adjust partitioning: two columns are needed.
scalingPropEditWidth = max(scalingPropEditSize(1), ...
    sheetDims(1) - 2 * commonGeom.sheetSideEdgeBuffer - 2 * commonGeom.frameSideEdgeBuffer);
argumentsEditWidth = scalingPropEditWidth - colDelta/3 - updateModelPushButtonSize(1);
widths = [argumentsEditWidth, updateModelPushButtonSize(1)];
[col,tmp,tmp,rowDelta] = ds_get_gui_columns(widths,commonGeom);

% all groupboxes on the page have the same width, which is the maximum of
% the 'needed' width and the width of the page
argGroupboxWidth = scalingPropEditWidth + 2 * commonGeom.frameSideEdgeBuffer;

% Edit height is the same for all edit fields on this tab
editHeight = 5 * commonGeom.editHeight;

% Position of scaling invariance groupbox
scalInvGroupboxHeight = commonGeom.frameTopEdgeBuffer ...
    + scalInvCheckboxSize(2) ...
    + fcnArgsOrderLabelSize(2) + rowDelta ...
    + editHeight ...
    + commonGeom.frameBottomEdgeBuffer;
cx = commonGeom.figSideEdgeBuffer + commonGeom.sheetSideEdgeBuffer;
cy = commonGeom.bottomSheetOffset + commonGeom.sheetBottomEdgeBuffer;
ctrlPos.scalInvGroupbox =  [cx,cy,argGroupboxWidth,scalInvGroupboxHeight];

% Position of Scaling propagation controls: edit, label and checkbox
cx = col(1);
cy = commonGeom.frameBottomEdgeBuffer;
ctrlPos.scalPropEdit = [cx, cy, scalingPropEditWidth, editHeight];
cx = col(1);
cy = cy + editHeight;
ctrlPos.scalPropLabel = [cx cy fcnArgsOrderLabelSize];
cy = cy + fcnArgsOrderLabelSize(2) + rowDelta;
ctrlPos.scalInvCheckbox = [cx cy scalInvCheckboxSize];

% Position of the function arguments groupbox
fcnArgGroupboxHeight = commonGeom.frameTopEdgeBuffer ...
    + 2 * fcnArgsOrderLabelSize(2) ...
    + 2 * (editHeight + rowDelta) ...
    + commonGeom.frameBottomEdgeBuffer;
cx = ctrlPos.scalInvGroupbox(1);
cy = ctrlPos.scalInvGroupbox(2) + scalInvGroupboxHeight...
    + commonGeom.textHeight;
ctrlPos.fcnArgGroupbox =  [cx,cy,argGroupboxWidth,fcnArgGroupboxHeight];

% Position of "additional pointer args" edit and "Select" pushbutton and label
cx = col(1);
cy = commonGeom.frameBottomEdgeBuffer;
ctrlPos.additionalArgsEdit = [cx, cy, argumentsEditWidth, editHeight];
cx = col(2);
ctrlPos.addPushButton = [cx cy updateModelPushButtonSize];
cx = col(1);
cy = cy + editHeight;
ctrlPos.additionalArgsLabel = [cx cy additionalArgsLabelSize];

% Position of "Pref. order of function args" edit and "UpdateFromModel"
% pushbutton and label
cx = col(1);
cy = cy + commonGeom.textHeight + rowDelta;
ctrlPos.fcnArgsOrderEdit = [cx, cy, argumentsEditWidth, editHeight];
cx = col(2);
ctrlPos.updateModelPushButton = [cx cy updateModelPushButtonSize];
cx = col(1);
cy = cy + editHeight;
ctrlPos.fcnArgsOrderLabel = [cx cy fcnArgsOrderLabelSize];

% Width and height of page
width = argGroupboxWidth + 2 * commonGeom.sheetSideEdgeBuffer;
height = ctrlPos.fcnArgGroupbox(4) ...
    + ctrlPos.scalInvGroupbox(4) ...
    + 2*commonGeom.textHeight ...
    + commonGeom.sheetBottomEdgeBuffer;
sheetDims = [width height];
% end of function FcnArgumentsCtrlPositions


%-------------------------------------------------------------------------------
% FcnCreateArgumentsPage creates the arguments page.
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%-------------------------------------------------------------------------------
function dlgdata = FcnCreateArgumentsPage(pageNum,dlgfig,dlgdata)

data = dlgdata.data;
ctrlPos = dlgdata.pageData{pageNum}.ctrlPos;

% Scaling invariance groupbox
Children.scalInvGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Scaling invariance'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.scalInvGroupbox);

Children.scalPropEdit  = uicontrol( ...
    'Parent',             Children.scalInvGroupbox, ...
    'BackGroundColor',   'w', ...
    'Min',                0, ...
    'Max',                2, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.scalPropEdit );

Children.scalPropLabel  = uicontrol( ...
    'Parent',             Children.scalInvGroupbox, ...
    'Style',              'text', ...
    'String',             'Scaling propagation:', ...
    'Position',           ctrlPos.scalPropLabel );

Children.scalInvCheckbox  = uicontrol( ...
    'Parent',             Children.scalInvGroupbox, ...
    'Value',              data.unscaledarguments, ...
    'Style',              'checkbox', ...
    'String',             'Scaling invariant', ...
    'Position',           ctrlPos.scalInvCheckbox );

% Function arguments groupbox
Children.fcnArgGroupbox = uipanel( ...
    'Parent',            dlgfig, ...
    'Title',            {'Function arguments'}, ...
    'Units',            'pixels', ...
    'Position',          ctrlPos.fcnArgGroupbox);

Children.updateModelPushButton = uicontrol( ...
    'Parent',            Children.fcnArgGroupbox, ...
    'Style',             'pushbutton', ...
    'String',            'Update', ...
    'Position',          ctrlPos.updateModelPushButton);

Children.fcnArgsOrderEdit  = uicontrol( ...
    'Parent',             Children.fcnArgGroupbox, ...
    'BackGroundColor',   'w', ...
    'Min',                0, ...
    'Max',                2, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.fcnArgsOrderEdit );

Children.addPushButton = uicontrol( ...
    'Parent',            Children.fcnArgGroupbox, ...
    'Style',             'pushbutton', ...
    'String',            'Add ... ', ...
    'Position',          ctrlPos.addPushButton);

Children.additionalArgsEdit  = uicontrol( ...
    'Parent',             Children.fcnArgGroupbox, ...
    'BackGroundColor',   'w', ...
    'Min',                0, ...
    'Max',                2, ...
    'Style',              'edit', ...
    'Position',           ctrlPos.additionalArgsEdit );

Children.fcnArgsOrderLabel = uicontrol( ...
    'Parent',             Children.fcnArgGroupbox, ...
    'Style',              'text', ...
    'String',             'Preferred order of function arguments:', ...
    'Position',           ctrlPos.fcnArgsOrderLabel);

Children.additionalArgsLabel = uicontrol( ...
    'Parent',             Children.fcnArgGroupbox, ...
    'Style',              'text', ...
    'String',             'Additional pointer arguments:', ...
    'Position',           ctrlPos.additionalArgsLabel);

dlgdata.pageData{pageNum}.children = Children;
% end of function FcnCreateArgumentsPage


%-------------------------------------------------------------------------------
% FcnManageArgumentsPage manages control actions on the arguments page of the dialog.
%
% INPUT ARGUMENTS
%   pageNum     number of current page
%   dlgfig      handle for dialog figure
%   dlgdata     dialog data
%   pageAction  action at one control of current page
%
% OUTPUT ARGUMENTS
%   dlgdata     modified dialog data
%   bModified   flag = 1, if dialog data are modified, =0 otherwise
%-------------------------------------------------------------------------------
function [dlgdata,bModified] = FcnManageArgumentsPage(pageNum,dlgfig,dlgdata,pageAction) %#ok<INUSL>

% prepare some needed data
Children = dlgdata.pageData{pageNum}.children;
data = dlgdata.data;

switch pageAction
    case 'updateModelPushButton'
        data = FcnUpdateFromModel(dlgdata);
        bModified = true;
    case 'fcnArgsOrderEdit'
        functionarglistList = deblank(get(Children.fcnArgsOrderEdit,'String'));
        % delete elements that appear twice or more often
        functionarglistList = FcnCheckArgumentsList(functionarglistList);
        % remove empty lines and blanks:
        if ~isempty(functionarglistList)
            functionarglistList(cellfun('isempty',tl_deblank(functionarglistList,2))) = [];
        end
        data.functionarglist = FcnGetDataStr(functionarglistList);
        bModified = true;
    case 'addPushButton'
        data = FcnSelectAdditionalArgs(data);
        if ~isempty(data.additionalarguments)
            addArgs = textscan(data.additionalarguments, '%s', 'delimiter', ',');
            % delete elements that appear twice or more often
            addArgs = FcnCheckArgumentsList(addArgs{:});
            addArgs(cellfun('isempty', addArgs)) = [];
            data.additionalarguments = FcnGetDataStr(addArgs);
        end
        bModified = true;
    case 'additionalArgsEdit'
        additionalargumentsList = get(Children.additionalArgsEdit,'String');
        % delete elements that appear twice or more often
        additionalargumentsList = FcnCheckArgumentsList(additionalargumentsList);
        % remove empty lines and blanks:
        if ~isempty(additionalargumentsList)
            additionalargumentsList(cellfun('isempty',tl_deblank(additionalargumentsList,2))) = [];
        end
        data.additionalarguments = FcnGetDataStr(additionalargumentsList);
        bModified = true;
    case 'scalInvCheckbox'
        data.unscaledarguments =  get(Children.scalInvCheckbox,'Value');
        bModified = true;
        % update of page necessary -> enable/disable scaling prop edit field
    case 'scalPropEdit'
        scalingpropagationStr = cellstr(get(Children.scalPropEdit,'String'));
        data.scalingpropagation = [scalingpropagationStr{:}];
        bModified = true;
    otherwise
        error(['Invalid action ''' pageAction'''']);
end %switch

dlgdata.data = data;
% end of function FcnManageArgumentsPage


%-------------------------------------------------------------------------------
% FcnUpdateArgumentsPage updates the controls of the arguments page.
%
% INPUT ARGUMENTS
%   dlgfig      handle of figure
%   dlgdata     dialog data
%   pageNum     number of page
%
% OUTPUT ARGUMENTS
%   - / -
%-------------------------------------------------------------------------------
function FcnUpdateArgumentsPage(dlgfig,dlgdata,pageNum)

data = dlgdata.data;
EnableOn = flag2str(dlgdata.bIsFullVs);

% early return if children are missing
Children = dlgdata.pageData{pageNum}.children;
if isempty(Children),
    return
end; %if

% invoke standard update function

bgColor = 'w';
fgColor = 'k';

% overwrite colors in stand alone mode
if ~dlgdata.bIsFullVs
    bgColor = get(dlgfig,'Color');
    fgColor = get(dlgfig,'Color');
end; %if

% bgColor for Scaling Propagation edit depends on scaling invariant checkbox
if data.unscaledarguments
    bgColorProp = bgColor;
    fgColorProp = fgColor;
else
    bgColorProp = get(dlgfig,'Color');
    fgColorProp = get(dlgfig,'Color');
end; %if

% converts comma separated string in cell array for display
functionarglistList = FcnGetDisplayList(data.functionarglist);
additionalargumentsList = FcnGetDisplayList(data.additionalarguments);

% enable/disable all controls
set(Children.scalPropEdit,...
    'Enable',          flag2str(dlgdata.bIsFullVs & data.unscaledarguments), ...
    'BackGroundColor', bgColorProp, ...
    'Foregroundcolor', fgColorProp, ...
    'String',          data.scalingpropagation, ...
    'Min',             0, ...
    'Max',             2);
set(Children.scalInvCheckbox,...
    'Enable', EnableOn, ...
    'Value',  data.unscaledarguments);
set(Children.updateModelPushButton,...
    'Enable', EnableOn);
set(Children.fcnArgsOrderEdit,...
    'String', functionarglistList, ...
    'BackGroundColor', bgColor, ...
    'Foregroundcolor', fgColor, ...
    'Enable', EnableOn);
set(Children.addPushButton,...
    'Enable',          EnableOn);
set(Children.additionalArgsEdit,...
    'String', additionalargumentsList, ...
    'BackGroundColor', bgColor, ...
    'Foregroundcolor', fgColor, ...
    'Enable', EnableOn);
% end of function FcnUpdateArgumentsPage


%-------------------------------------------------------------------------------
% FcnGetDisplayList converts data string in cell array
%
% INPUT ARGUMENTS
%   dataStr     comma separated list
%
% OUTPUT ARGUMENTS
%   list        cell array
%-------------------------------------------------------------------------------
function list = FcnGetDisplayList(dataStr)

if isempty(dataStr)
    list = {};
else
    numComma = numel(strfind(dataStr, ','));
    list = textscan(dataStr, '%s', numComma+1, 'Delimiter', ',');
    list = list{1};
end


%-------------------------------------------------------------------------------
% FcnGetDataStr converts cell array list in string
%
% INPUT ARGUMENTS
%   list        cell array
%
% OUTPUT ARGUMENTS
%   dataStr     comma separated list
%-------------------------------------------------------------------------------
function dataStr = FcnGetDataStr(list)

if isempty(list)
    dataStr = '';
else
    dataStr = list{1};
    for k = 2 : numel(list)
        dataStr = [dataStr ', ' list{k}]; %#ok<AGROW>
    end
end


%-------------------------------------------------------------------------------
% FcnUpdateFromModel manages "Update from Model" button on arguments page. Function deletes
%   wrong elements from arglist and adds elements that do not already exist.
%
% INPUT ARGUMENTS
%   dlgdata     dialog data
%
% OUTPUT ARGUMENTS
%   data        modified data
%-------------------------------------------------------------------------------
function data = FcnUpdateFromModel(dlgdata)

data = dlgdata.data;

inPortList  = {};
outPortList = {};
[h,objKind,objTypes] = tl_check_objects(sf('DataIn',dlgdata.model));
for i=1:numel(objTypes)
    switch objTypes{i}
        case 'SFInput'
            inPortList{end+1} = sf('get',h(i),'.name');
        case 'SFOutput'
            outPortList{end+1} = sf('get',h(i),'.name');
    end
end
% get old functionarglist
argList = FcnGetDisplayList(data.functionarglist);
% get in-/outports of the subsystem and write them in portList
portList = [inPortList outPortList]';

% get additional pointer parameters which are defined in additionalarguments property
% and prepend the keyword "$AdditionalParam:" (needed to distinguish from other parameters)
additionalArgList = {};
additionalarguments = FcnGetDisplayList(data.additionalarguments);
for elem = 1:length(additionalarguments)
    additionalArgList = [additionalArgList; {['AdditionalParam:', additionalarguments{elem}]}];    %#ok
end

% Supplement list with placeholder for instance struct.
bReuse = data.reuse;
if bReuse,
    portList = [portList;{'$InstanceStruct'}];
end; %if

% elements of both lists (portlist and additionalArgList) are added as long as they don't
% already exist
fullList = [portList; additionalArgList];
% Remove obsolete entries from old arglist: Only members of the fullList (i.e. inports,
% outports, $InstanceStruct, additional pointer arguments defined in additionalarguments)
% and $EVENTS, $RTOSEVENTS, $PARAMETERS are allowed.
% Also possible: $INPUT, $OUTPUT, $DDSTRUCTPOINTERS but these are replaced by the parameters
% in the portlist
allowedEntries = [fullList;{'$events'; '$rtosevents'; '$parameters'; '$ddstructpointers'}];
argList(~ismember(lower(argList),lower(allowedEntries))) = [];
% append new  entries at end of argument list
appIdx = find(~ismember(fullList,argList));
if ~isempty(appIdx),
    argList = [argList;fullList(appIdx)];
end; %if
data.functionarglist = FcnGetDataStr(argList);
return
% end of function  FcnUpdateFromModel


%-------------------------------------------------------------------------------
% FcnSelectAdditionalArgs manages "Select" button on arguments page. Function opens
%   DD Dialog where Struct-variables can be selected.
%
% INPUT ARGUMENTS
%   data        dialog data
%
% OUTPUT ARGUMENTS
%   data        modified data
%-------------------------------------------------------------------------------
function data = FcnSelectAdditionalArgs(data)

additionalarguments = FcnGetDisplayList(data.additionalarguments);
tmpSize = size(additionalarguments);
if tmpSize(1) < tmpSize(2)
    additionalarguments = additionalarguments';
end

% open DD dialog where variables can be selected
filter = {'OnlyRefParamStruct'};
varpath =  dsdd('SelectObject', ...
    ...'CurrentPath',      options.currentPath, ...
    'ObjectKind',       'variable', ...
    filter{:});

% Check if selected dd variable already is a member of the list.
if ~ismember(varpath,additionalarguments)
    % selected variable is not member of the list: add it
    data.additionalarguments = FcnGetDataStr([additionalarguments; cellstr(varpath)]);
else
    % selected variable is already in the list: don't add it
end
% end of function FcnSelectAdditionalArgs

%-------------------------------------------------------------------------------
% FcnCheckArgumentsList makes sure that no entry in list appraers twice. Always the last
%   one is deleted
%
% INPUT ARGUMENTS
%   oldlist     original arguments list
%
% OUTPUT ARGUMENTS
%   newlist     list where entries that appear twice are deleted
%-------------------------------------------------------------------------------
function newlist = FcnCheckArgumentsList(oldlist)

if isempty(oldlist)
    newlist = oldlist;
    return
else
    newlist = oldlist(1);
end
for m = 2 : length(oldlist)
    if ~ismember(oldlist(m), newlist)
        newlist = [newlist; oldlist(m)];       %#ok
    end
end
% end of function FcnCheckArgumentsList


%-------------------------------------------------------------------------------
% FcnChangeDefaultInput changes the string 'default' to 'default '
%
% INPUT ARGUMENTS
%   input   old string
%
% OUTPUT ARGUMENTS
%   input   if old string was 'default', it is now 'default '
%-------------------------------------------------------------------------------
function input = FcnChangeDefaultInput(input)

if strcmp(input,'default')
    input = 'default ';
end; %if
% end of function FcnChangeDefaultInput
